﻿/*==========================================================================================
*
* 导包部分 修改了
*
==========================================================================================*/
var storage = storages.create("AUTO");
/*==========================================================================================
*
* 全局变量和常量定义
*
==========================================================================================
*/
// let AUTO_BASE_URL = 'auto.ghyoutu.fun'; // API基础URL
// let AUTO_BASE_URL = 'caige.natapp1.cc'; // API基础URL
// let AUTO_BASE_URL = '192.168.101.7:1024'; // API基础URL
let AUTO_BASE_URL = 'www.baiyisw.cn/cai-api'; // API基础URL
//http 请求超时
http.__okhttp__.setTimeout(40000);
/*
==========================================================================================
*
* 应用配置
*
==========================================================================================
*/

let appName = "抖音"; // 软件名称
let appPackage = "com.ss.android.ugc.aweme"; // 软件包名
//本机 日志存放地
let logsPath = "/sdcard/Abandon/logs/" + 'log_' + new Date().toISOString().split('T')[0] + ".txt";
// 本机存储 未聊天用户
let notChatPath = "/sdcard/Abandon/notChatPath.txt"

var mainSwitch = false; // 主开关
var isDebug = false; // 调试模式
var isAuto = false; // 自动模式
var isAutoTask = false; // 自动任务模式
var isAutoTaskInterval = 1000; // 自动任务间隔
/*
==========================================================================================
*
* 常量定义
*
==========================================================================================
*/
/**
 * 点击操作后的全局延时
 */
const CLOCK_SLEEP = 1000; //
/**
 * 通用全局延时
 */
var GLOBAL_DELAY = 1000; // 
/**
 * 手机底部安全高度
 */
const BOTTOM_SAFE_HEIGHT = 300; //

/*
==========================================================================================
*
* 首页相关元素定位
*
==========================================================================================
*/
/**
 * 主页顶部加号，标识是否在消息页面
 */
const HOME_TOP_ADD = desc("密友时刻，按钮");

/**
 * 主页消息文本元素
 */
const HOME_MESSAGE_TEXT = clickable(false).desc("消息，按钮").text("消息").className("android.widget.TextView");

/**
 * 首页搜索图标
 */
const HOME_SEARCH_ICON = desc("搜索，按钮");
/**
 * 首页搜索图标
 */
const HOME_FRIEND_TEXT = clickable(false).desc("朋友，按钮").text("朋友").className("android.widget.TextView");;

/**
 * 首页按钮
 */
const HOME_BOTTOM_TEXT = desc("首页，按钮").clickable(false).text("首页").className("android.widget.TextView");

/**
 * 我的页面按钮
 */
const HOME_MY_BOTTOM_TEXT = desc("我，按钮").clickable(false).text("我").className("android.widget.TextView");

/*
==========================================================================================
*
*         用户交互元素定位
*
==========================================================================================
*/

/**
 * 筛选条件中的粉丝数量选项
 */
var SCREEN_NUM = text("不限");

/**
 * 用户类型筛选选项
 */
const SCREEN_USER_TYPE = text("企业认证");

/*
==========================================================================================
*
*        搜索页元素定位
*
==========================================================================================
*/
/**
 * 搜索按钮
 */
const SEARCH_BUTTON = text("搜索").desc("搜索").className("android.widget.TextView");

/**
 * 用户标签，不可点击状态
 */
const SCREEN_USER_TAB = text("用户").className("android.widget.Button");
/**
 * 用户标签，不可点击状态
 */
const SCREEN_SYN_TAB = text("综合").className("android.widget.Button");

/**
 * 搜索结果页筛选按钮
 */
const SEARCH_SCREEN = desc("筛选，按钮").className("android.view.ViewGroup");

/**
 * 搜索结果页筛选按钮
 */
const SEARCH_SCREEN_TWO = desc("筛选有新消息").className("android.view.ViewGroup");

/*
==========================================================================================
*
*           聊天界面元素定位
*
==========================================================================================
*/

/**
 * 发送按钮
 */
const SEND_MESSAGE_BUTTON = desc("发送").clickable(true).className("android.widget.ImageView");

/**
 * 标签
 */
const CHAT_FACE_BOTTOM = className("android.widget.Button").desc("表情");

/*
==========================================================================================
*
*           我的页面元素定位
*
==========================================================================================
*/
/**
 * 我的关注按钮
 */
const MY_FOLLOW_BUTTON = text("关注");

/*
==========================================================================================
*
* 用户页面元素定位
*
==========================================================================================
*/
// 日志文件路径，将会把日志写入该文件中 如文件不存在则创建
console.setGlobalLogConfig({ "file": logsPath, "append": true });
/**
 * 私信按钮
 */
const PRIVATE_MESSAGE_BUTTON = text("私信").desc("私信").className("android.widget.TextView");

/**
 * 关注按钮
 */
const FOLLOW_BUTTON = desc("关注按钮").text("关注按钮");

/**
 * 用户主页关注按钮
 */
const USER_HOME_BUTTON = text("关注").className("android.widget.TextView");

/**
 * 用户主页更多按钮
 */
const USER_MORE_BUTTON = desc("更多").className("android.widget.ImageView");

/**
 * 发送私信按钮
 */
const SEND_PRIVATE_MESSAGE_BUTTON = text("发私信").className("android.widget.TextView");

/**
 * 用户联系电话
 */
const USER_MOBILE = textContains("电话").className("android.widget.TextView");

/**
 * 用户电话内容
 */
const USER_MOBILE_CONTENT = textContains("呼叫").className("android.widget.TextView");

/**
 * 用户抖音号
 */
const USER_DY_ID = textContains("抖音号:").className("android.widget.TextView");

/**
 * 用户复制链接
 */
const USER_COPY_LIKE = textContains("复制链接").className("android.widget.TextView");

/**
 * 用户分享主页
 */
const USER_SHARE_HOME = text("分享主页").className("android.widget.TextView");

/*
==========================================================================================
*
* 聊天任务阻碍页 
*
==========================================================================================
*/

const HINDER_TEXT_001 = text("搜索作品").className("android.widget.EditText");

const HINDER_TEXT_002 = text("获赞").className("android.widget.TextView");


/*
==========================================================================================
*
* 任务变量
*
==========================================================================================
*/
/*
==========================================================================================
*
* 递归变量
*
==========================================================================================
*/
/**
 * 聊天框主ID
 */
var chat_frame = null;

/*
==========================================================================================
*
* 递归变量
*
==========================================================================================
*/
/**
 * 函数是否在执行 
 */
var IS_RUNNING = false;
/**
 * 标记函数 true 停止一切脚本 
 */
var SHOULD_STOP = false;
/**
 * 获取任务等待次数 初始化次数 20
 */
var TASK_GET_INTERVAL = 27;
/**
 * 获取任务等待最大次数 30
 */
var TASK_GET_INTERVAL_MAX = 30;
/**任务中转 */
var TASK_QUEUE = 0;
/** 获取不到任务次数叠加 */
var NOT_TASK_COUNT = 0;
/*
==========================================================================================
*
* 干扰弹窗特征集合
*
==========================================================================================
*/
/**
 * 获取查询弹窗等待次数
 */
var POPUPS_GET_TIME = 0;
/**
 * 获取查询弹窗等待最大次数
 */
var POPUPS_GET_TIME_MAX = 40;

let popups = [
    { query: text("登录发现更多精彩"), selector: className("android.widget.Button").text("以后再说") },
    { query: text("定位服务未开启"), selector: className("android.widget.Button").text("暂不") },
    { query: text("抖音 想访问你的通讯录"), selector: className("android.widget.Button").text("拒绝") },
    { query: text("授权提示"), selector: className("android.widget.Button").text("授权提示") },
    { query: text("我知道了"), selector: text("我知道了") },
    { query: text("暂不开启"), selector: text("暂不开启") },
    { query: text("开启定位，发现身边更多优惠"), selector: text("暂不开启") },
    { query: text("发现通讯录好友"), selector: text("暂时不要") },
    { query: text("个人信息保护指引"), selector: text("好的") },
    { query: text("去商店评分"), selector: text("好的") },
    { query: text("检测到更新"), selector: text("以后再说") },
    { query: text("跳过广告"), selector: text("跳过广告") },
    { query: text("悬浮窗播放功能上线啦"), selector: text("暂不使用") },
    { query: text("正在尝试开启"), selector: text("允许") },
    { query: text("以后再说"), selector: text("以后再说") },
];
/** 获取未读消息的过滤对象 */
const ignoreKeywords = ["置顶", "账号主体", "粉丝", "新朋友", "商家服务通知", "互动消息", "服务评价", "问题列表", "消息卡片", "钱包通知"];
/*
==========================================================================================
*
* 结束特征元素
*
==========================================================================================
*/

// 搜索用户界面无元素  无可用内容
const NOT_USABLE_CONTENT = text("没有搜索到相关的内容")
const NOT_USABLE_MAX = text("您的搜索次数已达上线")


/**
==========================================================================================
*
* HTTP请求函数
*
* @param {string} url - 请求的URL地址，不包含基础URL
* @param {Object} options - 请求选项，包含方法、头部、数据等
* @param {string} [options.method="GET"] - HTTP方法（GET、POST等）
* @param {Object} [options.headers] - HTTP头部信息
* @param {Object|string} [options.body] - 请求的主体内容，仅适用于POST请求
* @param {Object|string} [options.notRes] - 是否需要响应 | 默认需要
* @returns {Object} - 解析后的JSON响应
*
* @example
* // 发送GET请求
* var response = httpRequest('/api/data', { method: 'GET' });
* toastLog(response);
*
* @example
* // 发送POST请求
* var response = httpRequest('/api/data', {
*     method: 'POST',
*     headers: {
*         'Content-Type': 'application/json'
*     },
*     body: {
*         key: 'value'
*     }
* });
*
* @example
* // 发送POST请求，使用postJson快捷方式
* var response = httpRequest('/api/data', {
*     method: 'postJson',
*     body: {
*         key: 'value'
*     }*                                                            = 
* });*                                                              = 
*                                                                   =    
==========================================================================================
*/
function httpRequest(url, options) {
    // 确保options对象存在
    if (!options) {
        options = {};
    }
    // 设置默认方法为GET如果未指定
    if (!options.method) {
        options.method = "GET";
    }
    // 设置是否需要响应
    if (!options.notRes) {
        options.notRes = 'RES';
    }
    // 设置默认请求头为JSON，仅在POST请求时
    if (options.method && options.method.toLowerCase() === "post" && typeof options.body === 'object') {
        options.body = JSON.stringify(options.body);
        options.headers = { 'Content-Type': 'application/json' }; // 确保设置了正确的Content-Type
    }

    // 完整的URL
    const fullUrl = 'http://' + AUTO_BASE_URL + url;
    const errorCodes = { code: 400 };

    try {

        // 设置默认请求头为JSON，仅在POST请求时
        if (options.method.toLowerCase() === "postjson") {
            const r = http.postJson(fullUrl, options.body);
            if (options.notRes == 'RES') {
                return r.body.json(); // 解析JSON响应并进行处理
            }
            return;
        }
        // 发起HTTP请求，并假设它是同步的
        const response = http.request(fullUrl, options);
        if (options.notRes == 'RES') {
            // 处理响应
            return response.body.json(); // 解析JSON响应并进行处理  
        }
    } catch (error) {
        if (options.notRes == 'RES') {
            // 处理响应
            return errorCodes; //
        }

    }
}

/*
==========================================================
*
* 循环处理聊天界面的未读消息，直到没有未读消息为止。 聊天入口=
*
==========================================================
*/

mainSwitch = false; // 主开关
const overUser = "企缘智客Q"; //标记结束用户 积分商城——自定义设置 企缘智客Q 川农 万州烤鱼培训中心 
const startUser = "企缘智客K"; //标记结束用户 积分商城——自定义设置 企缘智客Q 川农 万州烤鱼培训中心
// processChatUntilNoMoreMessages({ isUpdate: true })
/**
 * 处理聊天界面中的未读消息，直到没有未读消息为止。
 * @param {Object} options - 函数选项
 * @param {boolean} options.isUpdate - 是否更新任务状态
 * @param {number} options.id - 任务ID
 */
function processChatUntilNoMoreMessages(options) {

    SHOULD_STOP = false; // 开始函数时，将停止标志设为 false
    var noMoreMessages = false; // 标记是否没有更多消息
    let overUserSeek = 1; // 超过用户搜索计数
    let UnreadCount = 0; // 超过未读消息计数


    // 如果不是更新任务状态，则尝试更新任务状态
    if (!options.isUpdate && !updateTaskStatus(options.id, 3)) {
        handleUpdateTaskStatusError(options.id); // 如果更新任务状态失败，处理错误
        return; // 退出函数，避免后续操作
    }

    sleep(1000);
    closePopup(); // 关闭弹窗

    // 到消息页面
    navigateToMessagePage()

    sleep(5000); // 短暂休眠
    closePopup(); // 再次关闭弹窗

    let allButton = text("全部").findOnce();
    if (allButton !== null) {
        clickElement(allButton, { type: 'function' }); // 点击“全部”按钮
    }

    scrollToTop(); // 返回顶部
    sleep(1000); // 短暂休眠

    // 发送消息 2188480726173756
    interiorMessageToUser("2082934031924186", 'qyzk_001');

    // 检查是否到达起点
    checkForCondition(190, () => {
        if (SHOULD_STOP) return true; // 如果标记为停止，则退出循环

        sleep(2000)
        if (descMatches(/返回,.*/).exists()) {
            back();
        }
        clickElement(text("以后再说").findOnce(), { type: 'function' }); // 处理弹窗
        sleep(5000)

        if (text(overUser).exists()) {
            toastLog("起点")
            downSlide(5)
            return true;
        }

        /** 点击消息按钮 */
        if (!desc("更多面板").exists()) {
            clickElement(HOME_MESSAGE_TEXT.findOnce(), { type: 'function', alarm: false, clickSleep: 3000 }); // 再次点击消息文本
        }

        swipe(device.width / 2, device.height * 0.7, device.width / 2, device.height * 0.2, 1000);
        overUserSeek++;
        return false; // 满足条件，退出 checkForCondition 的循环
    }, () => { noMoreMessages = true; });

    if (noMoreMessages) {
        sendEmail("严重消息", "当前设备" + getDeviceUniqueId + "" + "消息列表过多 无法加载 无法找到标记点", false);
        forceStopApp(appPackage)
        return false;
    }

    scrollToTop()

    while (true) {
        handleBackOrPopup(); // 处理返回操作或弹窗
        sleep(3000);

        if (UnreadCount >= 100) {
            // 发送消息 
            interiorMessageToUser("2188480726173756", 'qyzk_002');
            console.log("超过未读消息计数，退出");
            break;
        }

        let unreadMessage = processUnreadMessages();
        if (!unreadMessage || !unreadMessage.name) {
            UnreadCount++;
            continue;
        }

        // 获取未读消息的用户名
        let userName = unreadMessage.name;
        log("未读用户名", userName);

        sleep(1000); // 检查是否到达起点
        if (!userName || userName === startUser) continue;

        if (userName === overUser) {
            sleep(1000)
            clickElement(text(overUser));
            setInputText("qyzk_002") // 设置标语 qyzk_111
            let sendBtn = SEND_MESSAGE_BUTTON.findOnce();
            // 点击发送按钮，发送私信
            if (!clickElement(sendBtn, { type: 'function', clickSleep: 120, clickFrontSleep: 100 })) {
                clickElement(SEND_MESSAGE_BUTTON, { clickFrontSleep: 100, clickSleep: 120 })
            }
            back()
            break;
        } else {
            UnreadCount++;
        }

        writeLineToFile(userName);
    }

    scrollToTop()
    sleep(3000);

    while (true) {

        if (UnreadCount >= 100) {
            // 发送消息 
            interiorMessageToUser("2188480726173756", 'qyzk_002');
            console.log("超过未读消息计数，退出");
            break;
        }

        handleBackOrPopup(); // 处理返回操作或弹窗

        let unreadMsg = processUnreadMessages();
        if (unreadMsg === null || unreadMsg.name === null) {
            log("没有未读消息")
            UnreadCount++;
            continue;
        }

        //获取未读抖音名称
        let userName = unreadMsg.name;
        sleep(1000)
        if (!userName || userName === overUser) continue;

        log("K未读用户名", userName);

        //是否到达终点
        if (userName === startUser) {
            toastLog("标记结束")
            break;
        }
        writeLineToFile(userName);

        sleep(1000)
    }

    let lines = getMessageUserHomeUrl(); // 获取要聊天用户的首页路由
    if (lines && lines.length > 0 && lines !== null) {
        searchAndSendMessages(lines)
    }

    forceStopApp(appPackage); // 强制停止应用
    IS_RUNNING = false; // 标记当前函数结束运行
}

/**
 * 获取要聊天用户的首页路由
 * @returns {Array|boolean} - 返回用户首页路由数组或 false
 */
function getMessageUserHomeUrl() {
    try {
        let pathUserText = readFileContent();
        log("pathUserText", pathUserText)
        log(pathUserText)
        if (!pathUserText) {
            log("getMessageUserHomeUrl本地无数据，退出")
            return false;
        }
        // 发送请求
        const response = httpRequest('/autoGather/getMessageUserHomeUrl/' + pathUserText)
        log(response)
        if (!response.code === 0 || !response.data) {
            log("发送请求getMessageUserHomeUrl本地无数据，退出")
            return false;
        }

        return response.data;
    } catch (error) {
        console.error("获取要聊天用户的首页路由出错: ", error);
        return false;
    }
}
function searchAndSendMessages(notCollectList) {
    if (notCollectList.length === 0) {
        console.log("不收集的用户列表为空");
        return;
    }
    // 如果当前页面没有搜索按钮，则尝试导航到搜索页面
    if (!SEARCH_BUTTON.exists()) {
        checkForCondition(20, function (res) {
            if (SEARCH_BUTTON.exists()) {
                return true; // 满足条件，结束循环
            }
            let searchIcon = HOME_SEARCH_ICON.findOne(2200)
            if (searchIcon) {
                clickElement(searchIcon, { type: 'function' });  // 点击搜索图标
                return true;
            }
            navigateBack();
            clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });
            return false; // 继续循环直到满足条件
        }, () => { console.error("searchAndSendMessages搜索按钮未找到，退出"); });
    }

    for (let index = 0; index < notCollectList.length; index++) {
        let element = notCollectList[index];
        console.log("处理元素: " + element.douyinName);
        if (SHOULD_STOP) return;

        // 判断是不是在输入框页面  是的话就设置内容然后搜索
        checkForCondition(20, () => {
            if (SHOULD_STOP) return;
            let searchBottom = SEARCH_BUTTON.findOne(4200)

            if (searchBottom) {
                sleep(1000);
                setInputText(element.homeUrl);  // 设置搜索内容
                clickElement(searchBottom, { clickSleep: 1500, type: 'function' });
                return true;
            }

            if (descMatches(/返回,.*/).findOnce()) {
                sleep(5200)
                handleUnreadMessages()
            }

            if (
                text("获赞").exists()
                || text("搜索作品").exists()
                || text("发私信").exists()) {
                sleep(2000)
                back();
            }
            clickElement(HOME_SEARCH_ICON.findOnce(), { type: 'function' });  // 点击搜索图标

            clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });

            clickElement(desc('返回').findOnce(), { type: 'function', alarm: false, clickSleep: 300 }); // 再次点击消息文本

            return false; // 继续循环直到满足条件
        });


        let letterBottom = PRIVATE_MESSAGE_BUTTON.findOnce()
        if (letterBottom) {
            clickElement(letterBottom, { type: 'function' });
        } else {
            if (!clickUserMoreButton()) continue;
            clickElement(SEND_PRIVATE_MESSAGE_BUTTON);
        }

        sleep(4500)

        if (handleUnreadMessages()) {
            try {
                let file = open(notChatPath, "r"); // 以读取模式打开文件
                let content = file.read(); // 读取文件内容
                file.close(); // 关闭文件
                let dyList = content.split("$").filter(line => line.trim() !== ""); // 返回数组，去掉空行
                let dyIndex = dyList.indexOf(element.douyinName);
                if (dyIndex !== -1) { // 如果找到了索引
                    deleteLine(dyIndex + 1); // 删除指定行，因为lineNumber是从1开始的
                    toastLog("删除成功: " + element.douyinName); // 打印日志以便调试
                } else {
                    console.log("删除失败 未找到名称: " + element.douyinName); // 打印日志以便调试
                }
            } catch (error) {
                console.error("searchAndSendMessages处理未读消息时发生错误: ", error);
            }
        }
    }
}

/**
 *  无论在哪  到达获取好友聊天页面
 */
function searchFriendPage() {
    return checkForCondition(50, () => {
        if (SHOULD_STOP) return true; // 如果标记为停止，则退出循环
        clickElement(desc('返回').findOnce(), { type: 'function', alarm: false, clickSleep: 300 }); // 再次点击消息文本

        if (desc("取消,按钮").exists()) {
            return true;
        }

        clickElement(desc('返回').findOnce(), { type: 'function', alarm: false, clickSleep: 300 }); // 再次点击消息文本

        if (desc("更多面板").exists()) {
            // 点击搜索图标
            let searchIcon1 = className("android.widget.Button").desc("搜索").findOnce();
            clickElement(searchIcon1, { type: 'function' });
            sleep(3000);
            if (desc("取消,按钮").exists()) {
                return true;
            }
        }
        let _back_btn = descMatches(/返回,.*/).findOnce()
        if (_back_btn) {
            sleep(5000); // 暂停2.2秒  
            handleUnreadMessages(); // 处理未读消息  
            if (desc("取消,按钮").exists()) {
                return true;
            }
        }

        let messageBottom = HOME_MESSAGE_TEXT.findOnce();
        if (messageBottom != null) {
            clickElement(messageBottom, { type: 'function', alarm: false, clickSleep: 3000 }); // 再次点击消息文本
            if (desc("更多面板").exists()) {
                return true;
            }
        }
        back();
        return false; // 满足条件，退出 checkForCondition 的循环
    },);
}
/**
 * 发送消息 通过内部跳转  
 * @param {*} userId 
 * @param {*} message 
 */
function interiorMessageToUser(userId, message) {
    navUserChat(userId); // 导航到用户聊天  
    sleep(2000); // 暂停2秒  
    setInputText(message); // 设置要发送的文本内容  
    var sendBottom = SEND_MESSAGE_BUTTON.findOnce(); // 查找发送按钮  
    if (!clickElement(sendBottom, { type: 'function', clickSleep: 120, clickFrontSleep: 100 })) {
        clickElement(SEND_MESSAGE_BUTTON, { clickFrontSleep: 100, clickSleep: 120 }); // 点击发送按钮  
    }
    back(); // 返回上一级界面
}
/** 导航到聊天页 */
function navigateToMessagePage() {
    checkForCondition(20, () => {
        if (SHOULD_STOP) return true; // 如果标记为停止，则退出循环
        if (desc("更多面板").exists()) {
            return true;
        }
        let messageBottom = HOME_MESSAGE_TEXT.findOnce();
        if (messageBottom != null) {
            clickElement(messageBottom, { type: 'function', alarm: false, clickSleep: 3000 }); // 再次点击消息文本
            if (desc("更多面板").exists()) {
                return true;
            }
        }
        back();
        return false; // 满足条件，退出 checkForCondition 的循环
    }, () => { noMoreMessages = true; });
}
/**
 * 向下滑动指定次数
 * @param {number} times - 滑动次数
 */
function downSlide(times) {
    for (let i = 0; i < times; i++) {
        swipe(device.width / 2, device.height * 0.7, device.width / 2, device.height * 0.2, 1000);
        sleep(1000);
    }
}
/**
 * 备用的获取未读消息函数
 * @returns {Object|null} 未读消息对象或 null
 */
function getBackupUnread() {
    sleep(2000)
    let element = descMatches(/.*,未读.*/).findOnce();
    if (element) return getUnread(element);
    return null;
}
/**
 * 处理返回操作或弹窗
 */
function handleBackOrPopup() {
    if (descMatches(/返回,.*/).exists()) {
        sleep(5200)
        handleUnreadMessages()
    }

    let popup = text("以后再说").findOne(1200);
    if (popup !== null) {
        clickElement(popup, { type: 'function' }); // 处理弹窗
    }
}
/**
 * 处理未读消息
 * @returns {boolean} - 如果有未读消息，返回 true；否则返回 false
 */
function processUnreadMessages() {
    try {
        // 点击消息
        let messageBottom = HOME_MESSAGE_TEXT.findOnce();
        let backButton = descMatches(/返回,.*/).findOnce();

        if (backButton) {
            sleep(5200)
            handleUnreadMessages()
        }

        if (messageBottom != null && !backButton) {
            clickElement(messageBottom, { type: 'function', alarm: false }); // 再次点击消息文本
        }

        sleep(6000); // 缩短休眠时间以加快执行速度

        let startTime = new Date().getTime();
        let timeout = 12000; // 10秒超时时间
        let unreadBody = null; // 未读消息体
        let queryCount = 0; // 查询次数计数器
        let queryCountMAX = 2; // 查询次数计数器MAX
        while (new Date().getTime() - startTime < timeout) {
            sleep(3000); // 根据实际情况调整休眠时间
            // 查找未读消息元素
            unreadBody = findUnreadElement();
            if (unreadBody) {
                queryCount++;
            } else {
                let morePanel = desc("更多面板").findOnce();
                clickElement(morePanel, { type: 'function', alarm: false, clickSleep: 300 });
                sleep(2000); // 缩短休眠时间
                if (text("发起群聊").findOnce()) {
                    back()
                }
            }
            if (queryCount >= queryCountMAX) {
                log("找到消息体，退出循环");
                break; // 确保找到后退出循环
            }
        }

        // 检查是否找到未读消息体
        if (!unreadBody) {
            // log(unreadBody.name)
            return null;
        } else {
            toastLog(unreadBody.name.substring(0, 5));
        }
        log(unreadBody)
        return unreadBody;
    } catch (error) {
        console.error("处理未读消息时发生错误:", error);
        return null;
    }
}
function findUnreadElement() {

    let unreadElement = id("su7").findOnce();
    if (unreadElement) {
        unreadElement = findParentRecursively(id("su7").findOnce(), function (element) {
            return element.desc() && element.className() === "android.widget.Button";
        });
    }

    if (!unreadElement) {
        unreadElement = descMatches(/.*,未读.*/).findOnce();
    }

    return unreadElement ? getUnread(unreadElement) : null;
}
/**
 * 获取未读消息
 * @returns {Object} object
 */
function getUnread(unreadElement) {
    if (!unreadElement || !unreadElement.desc()) return false;

    if (ignoreKeywords.some(keyword => unreadElement.desc().includes(keyword))) {
        return false;
    }

    let splitText = unreadElement.desc().split(",")
    // 判断描述内容是否符合预期格式
    if (splitText.length <= 2) {
        return false;
    }
    // 返回消息对象，包含消息发送者和消息内容
    return {
        name: splitText[0],
        text: splitText.slice(1).join("")  // 合并第二项和第三项作为消息内容
    };
}
/** 
 * 返回到顶部
 */
function scrollToTop() {
    checkForCondition(350, function () {
        if (text("新朋友").exists()) {
            toastLog("到达顶部")
            return true; //
        }
        if (text("互动消息").exists()) {
            toastLog("到达顶部")
            return true; //
        }
        if (text("喊话").exists()) {
            toastLog("到达顶部")
            back()
            return true; //
        }

        if (!desc("更多面板").exists()) {
            let messageBottom = HOME_MESSAGE_TEXT.findOne(1200)
            if (messageBottom != null) {
                clickElement(messageBottom, { type: 'function', alarm: false, clickSleep: 3000 }); // 再次点击消息文本
            }
        }
        clickElement(text("以后再说").findOnce(), { type: 'function' });
        swipe(device.width / 2, device.height * 0.4, device.width / 2, device.height * 0.7, 500);
        return false
    })
}


/**
 * 聊天页刷新控件
 * @param {*} delay 
 */
function refWidget(delay) {
    delay = delay || 1000; // 设置延迟时间，默认1000ms

    let morePanel = desc("更多面板").findOnce();
    if (morePanel) {
        clickElement(morePanel, { type: 'function', alarm: false, clickSleep: 300 });
    }

    sleep(delay); // 缩短休眠时间

    let addFriendBtn = text("发起群聊").findOnce();
    if (addFriendBtn) {
        back()
    }
}
/**
 * 处理未读消息
 * @returns {boolean} - 如果有未读消息，返回 true；否则返回 false
 */
function handleUnreadMessages() {
    try {
        if (!descMatches(/返回,.*/).findOne(5000)) {
            log("不在返回界面");
            return false;
        }

        if (SHOULD_STOP) return; // 如果标记为停止，则退出函数
        let lastMessage = getLastMessage(); // 获取最后一条消息

        if (!lastMessage.sender || !lastMessage || !lastMessage.message) {
            sleep(3500)
            if (descMatches(/返回,.*/).findOnce()) {
                log("返回操作1");
                clickElement(descMatches(/返回,.*/).findOnce(), { type: 'function' })
            }
            return true;
        }

        let replyMessage = messageDispose(lastMessage); // 处理消息，生成回复内容

        if (replyMessage == null) {
            sleep(3500)
            if (descMatches(/返回,.*/).findOnce()) {
                log("返回操作2");
                clickElement(descMatches(/返回,.*/).findOnce(), { type: 'function' })
            }
            return true; //
        }
        // 回复消息
        setInputText(replyMessage); // 设置回复消息内容
        clickElement(SEND_MESSAGE_BUTTON); // 点击发送按钮
        sleep(3500)
        if (descMatches(/返回,.*/).findOnce()) {
            log("返回操作3");
            clickElement(descMatches(/返回,.*/).findOnce(), { type: 'function' })
        }
        return true; // 返回 true 表示处理了未读消息
    } catch (error) {
        console.error("处理未读消息时发生错误: ", error); // 捕获并打印错误信息
        return true;
    }
    return true; // 返回 true 表示处理了未读消息
}
// let startTime = new Date().getTime(); // 获取当前时间的毫秒数
// log(getLastMessage())
// let endTime = new Date().getTime(); // 获取执行后的当前时间
// let executionTime = endTime - startTime; // 计算执行时间，单位毫秒
// console.log("一共花费", executionTime / 1000, "秒");
/**
 * 获取最后一条消息的发送者和内容。
 * @returns {object|false} 返回包含最后一条消息发送者和内容的对象，如果出错或无消息返回 false。
 */
function getLastMessage() {
    try {
        if (SHOULD_STOP) return false; // 如果标记为停止，则退出函数

        clickElement(desc("更多面板").findOnce(), { type: 'function' }); // 点击消息文本
        clickElement(desc("关闭面板").findOnce(), { type: 'function' }); // 点击消息文本

        let startTime = new Date().getTime();
        let timeout = 10000; // 10秒超时时间
        let messageFrame = null;

        while (new Date().getTime() - startTime < timeout) {
            sleep(4000); // 根据实际情况调整休眠时间
            // 优先通过 id 查找未读消息元素
            messageFrame = id("srk").findOnce();
            if (messageFrame) {
                log("通过 'srk' 找到消息体");
                break;
            }

            // 通过描述查找头像元素
            let avatarMatch = descMatches(/.*的头像.*/).findOne(5000);
            if (avatarMatch) {
                messageFrame = findParentRecursively(avatarMatch, function (element) {
                    return element.className() === "androidx.recyclerview.widget.RecyclerView";
                });
                if (messageFrame) {
                    log("通过 '的头像' 找到消息体");
                    break;
                }
            }

            clickElement(desc("更多面板").findOnce(), { type: 'function' }); // 点击消息文本
            clickElement(desc("关闭面板").findOnce(), { type: 'function' }); // 点击消息文本
        }

        if (!messageFrame) {
            log("无法找到消息框元素");
            return false;
        }

        // 获取消息框内的所有消息元素
        let allMessages = messageFrame.children();

        if (!allMessages || allMessages.length === 0) {
            log("消息框内无消息");
            return false;  // 没有消息时返回 false
        }

        return extractMessageText(allMessages) || false;
    } catch (error) {
        console.error("获取最后一条消息时发生错误: ", error);
        return false;
    }
}


/**
 * 提取消息文本的主要函数。 
 * @param {Array} allMessages - 所有消息元素的数组。
 * @returns {object} 返回一个包含发送者和拼接后消息文本的对象，出错则返回 false。
 */
function extractMessageText(allMessages) {
    try {
        toastLog("匹配中...")
        if (SHOULD_STOP) return false; // 如果标记为停止，则退出函数

        let messagesList = []; // 用于存储消息文本
        let sender = null; // 初始化发送者变量
        let lastMessageElement = allMessages[allMessages.length - 1]; // 最后一条消息元素
        let avatarElement = findElementWithDescription(lastMessageElement, "的头像");
        let screenWidth = device.width; // 获取屏幕宽度

        //第一步  判断是否是自己发了最后一条消息
        if (avatarElement && avatarElement.bounds().centerX() > screenWidth / 2) {
            // 判断头像位置，如果在屏幕右侧，则认为是自己发送的消息
            log("最后消息是自己发送的，退出");
            return false; // 如果最后一条消息是自己发的，则不需要回复
        }

        // 获取发送者
        if (avatarElement && avatarElement.desc()) {
            sender = avatarElement.desc().replace("的头像", "");
        }
        //获取最后一条消息 并且检查是否合法
        // let endTextView = findElementRecursively(lastMessageElement, function (el) {
        //     return el.desc() && el.className() === "com.bytedance.ies.dmt.ui.widget.DmtTextView" && !filterOutUnwantedElements(el.desc());
        // });
        // if (!endTextView) {
        //     log("最后一条消息不可靠", endTextView)
        //     return false;
        // } else {
        //     //存入消息
        //     messagesList.push(endTextView.desc());
        // }

        // 检查给定消息元素及其子孙元素中是否包含描述用户头像的信息。
        for (var index = allMessages.length - 1; index >= 0; index--) {
            let messageBody = allMessages[index];

            sleep(200)

            let upperAvatarElement = findElementWithDescription(messageBody, "的头像");

            // 如果找到头像并且在屏幕左侧，则可能是发送者的消息
            if (upperAvatarElement && upperAvatarElement.bounds().centerX() <= screenWidth / 2) {

                if (!sender) { // 发送人未定  就用现在的发送人
                    sender = upperAvatarElement.desc().replace("的头像", "");
                }
                //到这说明 数据合格 并且未到达标记点  获取文本
                let textView = findElementRecursively(messageBody, function (el) {
                    return el.desc() && el.className() === "com.bytedance.ies.dmt.ui.widget.DmtTextView";
                });
                if (textView) messagesList.push(textView.desc());

            } else if (upperAvatarElement) {

                log("标记结束 跳出循环")
                break; // 如果找到的是自己的头像，跳出循环

            } else {

                let textView = findElementRecursively(messageBody, function (el) {
                    return el.desc() && el.className() === "com.bytedance.ies.dmt.ui.widget.DmtTextView";
                });

                if (textView) messagesList.push(textView.desc());

            }
        }

        // 逆序消息列表，使其按时间顺序排列
        messagesList.reverse();

        if (!sender || messagesList.length === 0) return false; // 如果没有发送人或消息列表为空，返回 false

        return {
            sender: sender,
            message: messagesList.join("")
        }; // 返回拼接后的消息文本
    } catch (error) {
        console.error("extractMessageText提取消息文本时发生错误: ", error);
    }

    return false;
}

/**
 * ===================================================================================
 * 消息处理函数，根据用户消息匹配关键字并返回对应的回复内容
 * const messageJson = {
 *  message: "你好我的手机号是",
 *  sender: '财哥'
 *}
 *====================================================================================
**/
function messageDispose(raw) {
    // 构造消息处理参数对象
    const messageJson = {
        userInput: raw.message || "", // 用户输入的消息
        userId: getUserId(), // 设备唯一标识
        sender: raw.sender // 消息发送者
    };
    // 发起网络请求，匹配关键字
    const response = httpRequest('/autoJargonBook/matchKeyword', { method: 'postJson', body: messageJson });
    // 根据响应结果返回数据或空字符串
    if (response.code === 0) {
        return response.data; // 匹配成功，返回匹配到的回复内容
    } else {
        return ''; // 匹配失败，返回空字符串
    }
}
/**
 * 过滤器库，用于排除不需要的文本。
 * @param {string} text - 要检查的文本。
 * @returns {boolean} 如果文本需要被排除，返回 true；否则返回 false。
 */
function filterOutUnwantedElements(text) {
    // 存储不需要的文本模式
    var unwantedPatterns = [
        "消息", "服务", "销售", "车", "此类问题出现", "私下交易", "刚刚", "智能客", "需要帮助", "亲在哪个",
        "已进入", "请看主页", "咨询", "亲", "我们主页", "这边帮您",
        "智能客服", "为您服务", "与您", "合法权益", "感谢您的", "会话记录", "我们的商家", "已经收到您的留言",
        "\\b\\d{2}:\\d{2}\\b" // 匹配时间格式 "HH:MM"
    ];

    // 创建正则表达式，忽略大小写
    var unwantedPattern = new RegExp(unwantedPatterns.join("|"), "i");

    // 测试文本是否匹配不需要的模式
    return unwantedPattern.test(text);
}
/**
 * 递归查找包含特定描述的元素
 * 示例使用：查找包含特定描述的元素
 * 
 * @param {Element} element - 要查找的根元素
 * @param {string} targetDesc - 目标描述文本
 * @return {Element|null} - 找到的包含特定描述的元素，或 null 如果未找到
 */
function findElementWithDescription(element, targetDesc) {
    return findElementRecursively(element, function (el) {
        return el.desc() && el.desc().includes(targetDesc);
    });
}
/**
 * 采集用户信息并向每个用户发送私信。 采集入口
 * @param {object} options 配置选项，包括城市和领域信息和发送文本等。
 */
function collectAndContactUsers(options) {

    SHOULD_STOP = false; // 开始函数时，将停止标志设为false
    try {
        // 初始化变量
        let swipeCount = 0; // 记录滑动次数
        let swipeCoordinates = 800; // 存储滑动参数
        let collectedUsers = []; // 存储采集到的用户数据
        let skipGathering = options.skipGathering || false; //默认要去一个一个聊天

        let cityParts = options.city.split('/');

        if (cityParts.length > 1) {
            options.city = cityParts[cityParts.length - 1]; // 取最后一个部分作为城市名称
        }

        // 检查是否在主页，如果是，则点击搜索按钮
        checkForCondition(50, function () {
            if (SHOULD_STOP) return true; // 检查是否应该停止

            if (SEARCH_BUTTON.exists()) {
                return true; // 满足条件，结束循环
            }

            let searchIcon = HOME_SEARCH_ICON.findOne(5000);

            if (searchIcon) {

                clickElement(searchIcon, { clickSleep: 4000, type: 'function' });

                if (SEARCH_BUTTON.exists()) {
                    return true; // 满足条件，结束循环
                }
            } else {
                back();
            }
            clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 5000 });
            return false; // 继续循环直到满足条件
        }, () => { sendEmail("collectAndContactUsers未找到搜索按钮", "默认任务异常", true) });

        // 判断是不是在输入框页面  是的话就设置内容然后搜索
        checkForCondition(30, () => { //回到输入框页面

            if (SHOULD_STOP) return;

            if (SCREEN_USER_TAB.exists()) {
                sleep(2000);
                setInputText(options.city + "" + options.domain);
                clickElement(SEARCH_BUTTON.findOnce(), { clickSleep: 1500, type: 'function' });
                return true;
            }

            if (SEARCH_BUTTON.exists() && !HINDER_TEXT_001.exists()) {
                let searchBottom = SEARCH_BUTTON.findOnce()
                if (searchBottom) {
                    sleep(2000);
                    setInputText(options.city + "" + options.domain);
                    clickElement(searchBottom, { clickSleep: 1500, type: 'function' });
                    return true;
                }
            } else {
                if (HINDER_TEXT_001.exists()) {
                    sleep(2000)
                    back();
                }
            }

            if (
                HINDER_TEXT_002.exists() || HINDER_TEXT_001.exists()
                || SEND_PRIVATE_MESSAGE_BUTTON.exists()) {
                sleep(2000)
                back();
            }

            if (descMatches(/返回,.*/).findOnce()) {
                sleep(2200)
                back()
            }

            clickElement(HOME_SEARCH_ICON.findOnce(), { type: 'function' });  // 点击搜索图标

            clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });

            return false; // 继续循环直到满足条件
        }, () => { sendEmail("G1631 未检测到搜索框", "默认任务异常", true) });

        if (SHOULD_STOP) return;

        closePopup()
        searchError()//  TODO: 检查是否上线

        if (options.fan !== null) {
            SCREEN_NUM = text(options.fan)
        }
        // 点击用户栏
        checkForCondition(20, function () {
            if (SHOULD_STOP) return true; // 检查是否应该停止
            closePopup()
            clickElement(SCREEN_USER_TAB, { clickSleep: 5000, clickFrontSleep: 5000 });
            if (SEARCH_SCREEN.exists()) {
                clickElement(SEARCH_SCREEN, { clickSleep: 2000, clickFrontSleep: 2000 });
                clickElement(SCREEN_NUM, { clickSleep: 3000 });
                clickElement(SCREEN_USER_TYPE, { clickSleep: 3000 });
                clickElement(SEARCH_SCREEN, { clickSleep: 3000 });
                return true; // 满足条件，结束循环
            } else if (SEARCH_SCREEN_TWO.exists()) {
                clickElement(SEARCH_SCREEN_TWO);
                clickElement(SCREEN_NUM, { clickSleep: 3000 });
                clickElement(SCREEN_USER_TYPE, { clickSleep: 3000 });
                clickElement(SEARCH_SCREEN_TWO,);
                return true; // 满足条件，结束循环
            }
            return false; // 继续循环直到满足条件
        }, () => { console.error("采集用户 点击用户栏 筛选") });

        closePopup()
        // 构建排除数据
        const keywords = options.Keyword ? options.Keyword.split(",") : false;

        enhanceFor(70, 1000, () => {
            try {
                if (SHOULD_STOP) return true; // 检查是否应该停止

                checkForCondition(20, () => { //回到输入框页面

                    if (SHOULD_STOP) return;

                    if (SCREEN_USER_TAB.exists() || SCREEN_SYN_TAB.exists()) {
                        sleep(2000);
                        return true;
                    }

                    if (SEARCH_BUTTON.exists() && !HINDER_TEXT_001.exists()) {
                        return true;
                    }

                    if (HINDER_TEXT_001.exists()) {
                        sleep(2000)
                        back();
                    }
                    if (HINDER_TEXT_002.exists() || HINDER_TEXT_001.exists()
                        || SEND_PRIVATE_MESSAGE_BUTTON.exists()
                    ) {
                        sleep(2000)
                        back();
                    }

                    if (descMatches(/返回,.*/).findOnce()) {
                        sleep(2200)
                        back()
                    }
                    return false; // 继续循环直到满足条件
                }, () => { sendEmail("循环下滑 采集用户 未检测到搜索框", "默认任务异常", true) });

                // 传入当前元素和条件函数，查找符合条件的父元素
                let userListContainer = findParentRecursively(FOLLOW_BUTTON.findOnce(), function (element) {
                    return element.className() === "androidx.recyclerview.widget.RecyclerView";
                });

                if (!userListContainer) {
                    backSearch()
                    if (!SCREEN_USER_TAB.exists() || !SCREEN_SYN_TAB.exists()) {
                        toastLog("未找到 RecyclerView ");
                        return true // 没有找到父元素 退出
                    }
                }

                let initialSnapshot = captureSnapshot(userListContainer);
                if (swipeCount !== 0) {
                    swipeMultipleTimes(swipeCoordinates, "up", 1, 3000);
                    sleep(3000)
                    userListContainer = findParentRecursively(FOLLOW_BUTTON.findOnce(), function (element) {
                        return element.className() === "androidx.recyclerview.widget.RecyclerView";
                    });

                    let newSnapshot = captureSnapshot(userListContainer);
                    if (initialSnapshot === newSnapshot) {
                        toastLog("页面内容未更新");
                        return true // 如果内容相同，则退出
                    }
                } else {
                    if (!updateTaskStatus(options.id, 3)) {
                        handleUpdateTaskStatusError(options.id);
                        return true;
                    }
                }

                if (!userListContainer) {
                    toastLog("未找到 userListContainer 元素，");
                    return true;
                }

                let userElements = userListContainer.children();
                if (!userElements) {
                    toastLog("未找到 userElements 元素，");
                    return true;
                }

                swipeCoordinates = userListContainer.bounds().bottom + (userElements[0].bounds().bottom - userElements[0].bounds().top); // 更新滑动参数

                for (var index = 1; index < userElements.length - 1; index++) {

                    backSearch()

                    sleep(200)
                    let item = userElements[index];

                    // 直接尝试获取粉丝描述信息 排除没有粉丝的 店铺账号和神秘账号过滤
                    let fanInfoElement = findElementRecursively(item, function (el) {
                        return el.desc() && el.desc().includes("粉丝");
                    });

                    if (!fanInfoElement || !fanInfoElement.desc()) continue;

                    let userInfo = {}
                    let description = fanInfoElement.desc();
                    userInfo = getUserInfo(description, keywords);

                    // 额外的属性检查，例如是否需要采集
                    if (userInfo.notGather) continue;

                    clickElement(fanInfoElement, { type: 'function', minDistance: 50 });

                    if (text("私密账号").exists()) {
                        toastLog("私密账号，跳过")
                        backSearch()
                        continue;
                    };

                    if (text("您的访问被拒绝").exists()) {
                        sleep(2000)
                        clickElement(text("确定"));
                    }

                    if (!clickUserMoreButton()) continue;

                    //采集抖音号
                    userInfo.douyinNum = getDouYinNum()
                    if (!userInfo.douyinNum) userInfo.douyinNum = "未知抖音号"

                    //获取链接
                    let homeUrl = getHomeUrl()

                    if (!homeUrl) backSearch()

                    userInfo.homeUrl = homeUrl         //主页链接赋值
                    let replyMessage = options.verbal //回复内容赋值

                    if (!skipGathering) {
                        let letterBottom = PRIVATE_MESSAGE_BUTTON.findOnce()
                        if (letterBottom) {
                            clickElement(letterBottom, { type: 'function', clickFrontSleep: 800 });
                            sendMessageToUser(replyMessage, userInfo);
                        } else {
                            if (!clickUserMoreButton()) continue;
                            clickElement(SEND_PRIVATE_MESSAGE_BUTTON, { clickFrontSleep: 800 });
                            sendMessageToUser(replyMessage, userInfo);
                        }
                    } else {
                        backSearch()
                    }
                    collectedUsers.push(userInfo);
                }
                swipeCount++;
            } catch (error) {
                console.error('在采集用户信息时发生异常：', error);
                // sendEmail("在采集用户信息时发生异常：" + error, "默认任务异常")
            } finally {
                //采集数据
                let rawJson = {
                    json: JSON.stringify(collectedUsers),
                    city: options.city,
                    keyword: options.domain,
                    userId: getUserId()
                };
                httpRequest('/autoGather/processAndStoreDyData', { method: 'postJson', body: rawJson, notRes: 'yes' })
            }
        });
        if (SHOULD_STOP) return;
        //获取数据库的数据进行发送 //不采集就直接上传
        // if (!skipGathering) {
        // closePopup()
        // getBaseDataGather(options)
        // }
    } catch (error) {
        // 捕获并处理异常
        console.error('采集用户 程序发生异常：', error);
        sendEmail("采集用户 程序发生异常：" + error.message, "默认任务异常");
    } finally {
        sleep(20000)
        if (TASK_QUEUE >= 2) {
            TASK_QUEUE = 0;
            processChatUntilNoMoreMessages({ isUpdate: true });
        } else {
            TASK_QUEUE++;
        }
        // 重置运行标志，无论是否发生异常
        IS_RUNNING = false;
    }
}
/**
 * 返回搜索页面并执行相关操作
 */
function backSearch() {

    // 检查条件，最多尝试30次
    checkForCondition(30, () => { //回到输入框页面

        // 如果 SCREEN_USER_TAB 存在，表示已经在输入框页面，返回 true
        if (SCREEN_USER_TAB.exists()) {
            return true;
        }

        // 如果 SEARCH_BUTTON 存在且 HINDER_TEXT_001 不存在，返回 true
        if (SEARCH_BUTTON.exists() && !HINDER_TEXT_001.exists()) {
            return true;
        }
        // 如果 HINDER_TEXT_002、HINDER_TEXT_001 或 SEND_PRIVATE_MESSAGE_BUTTON 存在，等待2秒后返回上一页
        if (HINDER_TEXT_002.exists() || HINDER_TEXT_001.exists() || SEND_PRIVATE_MESSAGE_BUTTON.exists()) {
            sleep(2000);
            back();
        }

        // 如果描述匹配 "返回,.*" 的元素存在，等待2.2秒后返回上一页
        if (descMatches(/返回,.*/).findOnce()) {
            sleep(2200);
            back();
        }
        // 点击搜索图标
        clickElement(HOME_SEARCH_ICON.findOnce(), { type: 'function' });

        // 点击 HOME_BOTTOM_TEXT，设置延迟时间和点击后的等待时间
        clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });

        return false; // 继续循环直到满足条件sendEmail("G1631 未检测到搜索框", "默认任务异常", true)
    }, () => { log("G1631 未检测到搜索框") });
}
/**
 * 获取基础数据并进行处理
 * @param {Object} options - 包含城市、领域和用户ID的选项对象
 * @param {string} options.city - 城市名称
 * @param {string} options.domain - 领域关键词
 * @param {string} options.verbal - 是否发送私信的标志
 * @returns {boolean} - 返回操作是否成功的布尔值
 */
function getBaseDataGather(options) {
    try {
        // 构建请求的原始JSON数据
        let rawJson = {
            city: options.city, // 城市名称
            keyword: options.domain, // 领域关键词
            userId: getUserId() // 获取用户ID
        };
        // 发送HTTP请求，获取过滤后的帖子数据
        const response = httpRequest('/autoGather/filterPostsByNotGather', {
            method: 'postJson', // 请求方法为POST，并发送JSON数据
            body: rawJson // 请求体为构建的原始JSON数据
        });

        // 检查响应状态码，如果为0表示成功
        if (response.code === 0) {
            // 对获取的数据进行搜索并发送私信
            searchAndSendPrivateMessages(response.data, options.verbal);
            return true; // 返回操作成功
        }

        return false; // 返回操作失败
    } catch (error) {
        // 捕获并记录异常
        console.log("getBaseDataGather获取数据异常", error);
        return false; // 返回操作失败
    }
}
/**
 * 对一组用户数据进行搜索并发送私信。
 * @param {Array} userList - 用户数据数组
 * @param {string} messageContent - 要发送的私信内容
 */
function searchAndSendPrivateMessages(userList, messageContent, skipGathering) {
    try {

        // 确保 baseData 不为 null 并且具有 length 属性
        if (!userList || !userList.length || userList.length === 0) {
            return false
        }

        if (SHOULD_STOP) return;

        let totalUsers = userList.length;

        // 如果当前页面没有搜索按钮，则尝试导航到搜索页面
        if (!SEARCH_BUTTON.exists()) {
            checkForCondition(20, function (res) {
                if (SEARCH_BUTTON.exists()) {
                    console.log("提前结束 检查是否在主页");
                    return true; // 满足条件，结束循环
                }
                let searchIcon = HOME_SEARCH_ICON.findOne(2200)
                if (searchIcon) {
                    clickElement(searchIcon, { type: 'function' });  // 点击搜索图标
                    return true;
                }
                navigateBack();
                clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });
                return false; // 继续循环直到满足条件
            }, () => { sendEmail("发送消息未检出到搜索图标", "默认任务异常", true); });
        }
        for (var index = 0; index < totalUsers; index++) {

            let user = userList[index];
            let shouldExit = false;  // 标记是否需要退出循环

            if (SHOULD_STOP) return;

            // isSearchError() //  TODO: 检查是否上线

            // 判断是不是在输入框页面  是的话就设置内容然后搜索
            checkForCondition(20, () => {

                if (SHOULD_STOP) return;
                let searchBottom = SEARCH_BUTTON.findOne(2200)
                if (searchBottom) {
                    sleep(1000);
                    if (!isEmpty(user.homeUrl)) {
                        let setStrRes = setInputText(user.homeUrl);  // 设置搜索内容
                        if (!setStrRes) {
                            shouldExit = true
                            return true;
                        }
                        clickElement(searchBottom, { clickSleep: 1500, type: 'function' });
                        return true;
                    }
                }
                navigateBack();
                let searchIcon = HOME_SEARCH_ICON.findOne(1200)
                if (searchIcon) {
                    clickElement(searchIcon, { type: 'function' });  // 点击搜索图标
                }
                clickElement(HOME_BOTTOM_TEXT, { alarm: false, delayTime: 4000, clickSleep: 4000 });

                return false; // 继续循环直到满足条件
            }, () => { sendEmail("发送消息未检测到输入框页面", "默认任务异常", true); });

            if (SHOULD_STOP) return;

            if (shouldExit) {
                continue;  // 如果需要退出，则跳出循环
            }

            let letterBottom = PRIVATE_MESSAGE_BUTTON.findOne(800)
            if (letterBottom) {
                clickElement(letterBottom, { type: 'function' });
                sendMessageToUser(messageContent, user);
            } else {
                if (!clickUserMoreButton()) continue;
                clickElement(SEND_PRIVATE_MESSAGE_BUTTON);
                sendMessageToUser(messageContent, user);
            }
        }
    } catch (error) {
        console.error('程序发生异常：', error);
    }
}
/**
 * 获取抖音号
 * @returns String dyNum
 */
function getDouYinNum() {
    // 如果抖音号为空，则尝试采集抖音号
    let dyNum = USER_DY_ID.findOne(5000).text();  // 获取抖音号文本
    let regex = /抖音号:\s*(\w+)/;
    let match = dyNum.match(regex);
    return match ? match[1] : null;  // 设置抖音号
}
/**
 * 获取主页链接
 * @returns String dyNum
 */
function getHomeUrl() {
    let shareBtn = USER_SHARE_HOME.findOne(1200)
    if (!shareBtn) {
        return null;
    }
    //主页连接为空
    let clickRes = clickElement(shareBtn, { type: 'function' })
    if (!clickRes) {
        return null;
    }
    clickElement(USER_COPY_LIKE, { delayTime: 3000 })
    return getClips();
}
/**
 * 根据输入字符串提取用户信息。
 * @param {string} userInfoString - 来自UI的用户信息字符串，格式应为"抖音名，粉丝数，公司名称"
 * @param {string} domain - 用户所属领域
 * @returns {object} 包含抖音名、粉丝数和公司名称的用户信息对象
 */
function getUserInfo(userInfoString, keywords) {

    let user = {
        douyinName: "", // 用户抖音名
        fansCount: 0, // 初始化粉丝数
        company: "", // 初始化公司名 
    };

    // 检查输入字符串是否为空或类型是否不为字符串
    if (!userInfoString || typeof userInfoString !== 'string') {
        user.notGather = true; // 标记为不采集
        return user;
    }



    // 检查公司名称是否包含排除关键词
    const exclusionKeywords = ["警察", "法院", "交警", "消防", "账号", "人民"];

    if (exclusionKeywords.some(keyword => userInfoString.includes(keyword))) {
        user.notGather = true; // 标记为不采集
        return user;
    }

    // 检查是否包含指定关键词
    if (keywords && !keywords.some(keyword => userInfoString.includes(keyword))) {
        user.notGather = true; // 标记为不采集
        return user;
    }

    let parts = userInfoString.split("，");
    // 检查分割后的数组长度是否小于2
    if (parts.length < 2) {
        user.notGather = true; // 标记为不采集
        return user;
    }

    // 设置用户抖音名
    user.douyinName = parts[0] || "未知";

    // 检查是否私信过
    if (!checkUserIsUsed(user.douyinName)) {
        user.notGather = true; // 标记为不采集
        return user;
    }

    // 提取粉丝数，假定它总是位于第二个位置
    // 提取粉丝数
    const fansCountMatch = parts[1].match(/\d+/);
    user.fansCount = fansCountMatch ? parseInt(fansCountMatch[0], 10) : 0;

    // 如果信息完整包含公司名称，则处理公司名称
    if (parts.length === 3) {
        user.company = parts[2];
        const lastIndex = user.company.lastIndexOf("按钮");
        if (lastIndex !== -1) {
            user.company = user.company.substring(0, lastIndex);
        }
    } else {
        user.notGather = true; // 标记为不采集
        return user;
    }
    return user;
}
/**
 * 检查是否使用过
 * @param {*} dyName 
 * @returns 1 代表使用 0 代表未使用
 */
function checkUserIsUsed(dyName) {

    let messageJson = {
        userId: getUserId(),  // 获取当前用户 ID
        dyName: dyName,  // 获取用户的抖音名称
    };

    // 发送请求，将私信发送记录存储到数据库
    const res = httpRequest('/notes/checkUserIsUsed', { method: 'postJson', body: messageJson });
    if (res.code === 0) {
        return res.data
    }
    return false
}
/**
 * 发送信息 以及更新数据库
 * @param {string} messageContent - 要发送的私信内容
 * @param {Object} user - 用户对象，包含用户信息
 * @param {boolean} isClickMessage - 标志是否需要点击私信
 */
function sendMessageToUser(messageContent, user) {

    // 在私信输入框中输入要发送的文本内容
    setInputText(messageContent);

    // 点击发送按钮，发送私信
    clickElement(SEND_MESSAGE_BUTTON);

    checkForCondition(20, function () {
        if (descMatches(/返回,.*/).exists() || text("搜索作品").exists()) {
            navigateBack(1300, 2);
        }
        sleep(2200)
        if (SEARCH_BUTTON.exists()) {
            return true; // 满足条件，结束循环
        }
        sleep(2200)
        if (text("获赞").exists()) {
            back();
        }
        return false; // 继续循环直到满足条件
    }, () => { sendEmail("RecyclerView按钮", "默认任务异常", true) });



    // 构建存储私信发送记录的 JSON 对象
    let messageJson = {
        userId: getUserId(),  // 获取当前用户 ID
        dyName: user.douyinName,  // 获取用户的抖音名称
    };
    // 发送请求，将私信发送记录存储到数据库
    httpRequest('/notes/store', { method: 'postJson', body: messageJson, notRes: 'yes' });

}
/**
 * 判断是否点击成功
 * @returns 
 */
function clickUserMoreButton() {
    let moreButtonClicked = false;
    checkForCondition(5, function () {
        if (SEARCH_SCREEN.exists()) {
            moreButtonClicked = false;
            return true;
        }
        if (HINDER_TEXT_001.exists()) {
            navigateBack()
        }

        if (text("您的访问被拒绝").exists()) {
            sleep(2000)
            clickElement(text("确定"));
        }

        if (SEND_PRIVATE_MESSAGE_BUTTON.exists()) {
            moreButtonClicked = true
            return true;
        }

        clickElement(USER_MORE_BUTTON.findOnce(0), { type: 'function' });
    }, () => { log("发送私信没有找到用户头上三个点"); });
    return moreButtonClicked;
}
/**-----------------------------封裝全局函數------------------------------- */
/**
 * 设置Android设备上的文本输入框的文本。
 * @param {string} text - 要设置的文本内容。
 */
function setInputText(text) {
    if (!text) {
        console.error("尝试设置的文本为空，操作已取消");
        return false;
    }

    let inputField = className("android.widget.EditText").findOne(3000);  // 查找输入框

    if (inputField) {
        inputField.setText(text);  // 设置文本
        //  log("文本已设置: " + text);
    } else {
        console.error("未找到输入框，无法设置文本");
    }

    delayExecution();  // 操作后的额外延迟，可用于确保UI稳定
    return true;
}
/**
 * 在指定元素的边界内随机点击，并等待一段时间。
 * @param {Object} element - 要点击的元素。
 * @param {object} options - 参数对象，包括：
 *  - delayTime: 查找元素超时时间，默认10000毫秒。
 *  - type: 'function'表示已经查找好的元素，'text'表示需要查找的元素，默认为'text'。
 *  - safe: 是否避免点击接近设备底部的区域，默认为false。
 *  - clickFrontSleep: 点击前延时，默认200毫秒。
 *  - clickSleep: 点击后延时，默认500毫秒。
 *  - alarm: 如果找不到元素是否报警，默认为true。
 *  - minDistance :安全距离 默认为 1
 * @returns {boolean} 如果成功执行点击操作，则返回true；否则返回false。
 */
function clickElement(element, options) {
    // 检查元素是否存在
    if (!element) {
        return false;
    }
    options = options || {};

    let delayTime = options.delayTime || 10000;
    let type = options.type || 'text';
    let safe = options.safe || false;
    let clickFrontSleep = options.clickFrontSleep || 200;
    let clickSleep = options.clickSleep || 500;
    let alarm = options.alarm !== undefined ? options.alarm : true;
    let bottomSafeHeight = options.bottomSafeHeight || 200;
    let minDistance = options.minDistance || 1
    let elementName = '';
    let foundElement = type === "function" ? element : element.findOne(delayTime);
    if (!foundElement) {
        if (alarm) {
            console.error("未找到元素或元素不可点击", element);
        }
        return false;
    }

    if (foundElement.desc()) {
        elementName = foundElement.desc()
    } else {
        if (foundElement.text()) {
            elementName = foundElement.text()
        }
    }
    // 点击前延时
    sleep(clickFrontSleep);
    // 获取元素边界
    let rect = foundElement.bounds();
    let centerX = rect.centerX();
    let centerY = rect.centerY();

    // 安全区域检查
    if (safe && centerY > device.height - bottomSafeHeight) {
        log("点击位置接近设备底部，已取消操作");
        return false;
    }

    // 执行点击操作
    click(centerX, centerY);
    log("——>", elementName);
    // 点击后延时
    sleep(clickSleep);
    return true;
}
/**
 * 捕获指定元素的第一个子元素的文本内容。
 * 如果有子元素，返回第一个子元素的文本；如果没有子元素，返回空字符串。
 * @param {Object} element - 要检查的元素对象。
 * @returns {string} 元素的子元素文本内容或空字符串。
 */
function captureSnapshot(element) {
    // 检查元素是否存在
    if (!element) {
        console.error("捕获快照失败：提供的元素不存在");
        return "";
    }

    // 获取元素的子元素列表
    let children = element.children();
    // 创建一个数组来存放文本
    let texts = [];

    // 检查是否有子元素
    if (children && children.length > 0) {
        // 确保子元素具有文本属性，并将其添加到数组中
        if (children[0] && children[0]) {
            texts.push(children[0]);
        }
        // 将数组中的文本元素合并成一个字符串并返回
        return texts.join("");
    } else {
        // 如果没有子元素，返回空字符串
        return "";
    }
}

/**
 * 检查是否存在搜索错误
 * @returns {boolean} - 如果检测到搜索错误，则返回 true，否则返回 false
 */
function searchError() {
    let errorMsg = "";

    // 检查是否存在不可用内容或达到最大限制
    if (NOT_USABLE_CONTENT.exists() || NOT_USABLE_MAX.exists()) {
        errorMsg = "没有搜索到相关内容异常";
    }

    // 单独检查是否达到最大限制
    if (NOT_USABLE_MAX.exists()) {
        errorMsg = "搜索次数上限异常";
    }

    // 如果 errorMsg 不为空，发送邮件并返回 true
    if (errorMsg) {
        sendEmail(errorMsg + "采取措施" + '\n' + "半小时内该设备不获取新任务", "账号异常", true);
        sleep(30 * 60000)
        return true;
    }

    return false;
}
/**
 * 全局延时函数，提供可选的延时时间。
 * @param {number} [time] 延时时间（毫秒），如果未指定，则使用默认延时时间。
 */
function delayExecution(time) {
    // 设置默认延时时间
    let delayTime = (typeof time === 'number' && time >= 0) ? time : GLOBAL_DELAY;
    // 日志记录延时操作，帮助调试
    if (delayTime > 1500) log("延时 " + delayTime + " 毫秒");
    // 执行延时
    sleep(delayTime);
}
/**
 * 执行返回操作，并在返回前后添加延时。
 * @param {number} [delayTime=1000] 延时时间（毫秒），默认为1000毫秒。
 * @param {number} [backCount=1] 返回次数，默认为1次。
 */
function navigateBack(delayTime, backCount) {
    // 设置默认值
    backCount = backCount || 1;  // 默认返回1次
    delayTime = delayTime || 600;  // 默认延时1000毫秒

    // 执行返回操作
    for (var i = 0; i < backCount; i++) {

        log(" " + (i + 1) + " 次返回，共 " + backCount + " 次");

        // 在返回前添加延时
        sleep(delayTime);

        // 执行返回操作
        back();

        // 如果不是最后一次返回，则在返回后添加延时
        if (i < backCount - 1) {
            sleep(delayTime);
        }
    }
}
/**
 * 执行指定次数的操作，根据操作结果决定是否提前终止。
 * @param {function} actionFunc 要执行的操作函数，应返回一个布尔值指示是否终止循环。
 * @param {number} times 执行次数，默认为1次。
 * @param {number} delayTime 延时时间（毫秒），默认为2000毫秒。
 */
function enhanceFor(times, delayTime, actionFunc) {
    // 参数验证
    if (typeof actionFunc !== 'function') {
        console.error("无效的参数: actionFunc 应为函数");
        return; // 直接返回，避免程序崩溃
    }
    times = (typeof times === 'number' && times > 0) ? times : 1;  // 如果times未指定或无效，使用默认值1
    delayTime = (typeof delayTime === 'number' && delayTime > 0) ? delayTime : 500;  // 如果delayTime未指定或无效，使用默认值2000

    for (var i = 0; i < times; i++) {
        log("执行第 " + (i + 1) + " 次操作");
        try {
            if (actionFunc()) {
                break;
            }
        } catch (error) {
            console.error("在执行 actionFunc 时发生错误:", error);
            continue; // 跳过当前循环，继续下一次操作
        }


        sleep(delayTime);  // 操作后的延时
    }
}

/**
 * 执行指定次数的操作，并检查条件是否满足。
 * 
 * @param {number} times - 执行次数
 * @param {function} conditionFunc - 检查条件的函数，应返回一个布尔值
 * @param {function} alarmFunc - 条件未满足时执行的警告或处理函数
 * 
 * @example
 * // 检查条件函数示例，返回一个随机的布尔值
 * function checkCondition() {
 *     return Math.random() < 0.5;
 * }
 * 
 * // 警告函数示例，当条件未满足时执行
 * function showAlarm() {
 *     log("条件未满足，执行警告或处理操作");
 * }
 * 
 * // 使用 checkForCondition 函数检查条件
 * checkForCondition(5, checkCondition, showAlarm);
 */
function checkForCondition(times, conditionFunc, alarmFunc) {
    // 参数验证
    if (typeof times !== 'number' || times <= 0 || typeof conditionFunc !== 'function') {
        console.error("无效的参数: times 应为大于 0 的数字，conditionFunc 应为函数");
        return; // 直接返回，避免程序崩溃
    }

    let conditionMet = false;

    for (var attempt = 0; attempt < times; attempt++) {
        try {
            if (conditionFunc()) {
                conditionMet = true;
                break;
            }
            sleep(CLOCK_SLEEP); // 暂停一段时间后再次尝试
        } catch (error) {
            console.error("在执行条件函数时发生错误:", error);
            sendEmail("在执行条件函数时发生错误" + error, "系统错误", true)
        }
    }

    if (!conditionMet) {
        alarmFunc(); // 条件未满足时执行警告或处理函数
    }
}
/**
 * 检查值是否为空。
 * 空的定义包括：null、undefined、空字符串（忽略空白字符）、空数组、空对象、NaN、无效日期。
 * 可选地提供一个自定义校验函数，用于扩展或覆盖标准的空值检查。
 * @param {*} value - 要检查的值。
 * @param {function} [fn] - 自定义校验函数（可选）。
 * @returns {boolean} 如果值为空，则返回 true，否则返回 false。
 */
function isEmpty(value, fn) {
    // 如果提供了自定义校验函数，使用该函数进行检查
    if (typeof fn === "function") {
        return fn(value);
    }
    // 检查 null 或 undefined
    if (value == null) {
        return true;
    }
    // 检查字符串（考虑空白字符）
    if (typeof value === "string") {
        return value.trim() === "";
    }
    // 检查数组
    if (Array.isArray(value)) {
        return value.length === 0;
    }
    // 检查对象（不包括类似日期这样的对象）
    if (typeof value === "object" && !(value instanceof Date)) {
        for (var key in value) {
            if (Object.prototype.hasOwnProperty.call(value, key)) {
                return false;
            }
        }
        return true;
    }
    // 检查数字是否为 NaN
    if (typeof value === "number") {
        return isNaN(value);
    }
    // 检查无效的日期
    if (value instanceof Date) {
        return isNaN(value.getTime());
    }
    // 其他情况认为不为空
    return false;
}

/**
 * 根据给定距离和方向进行多次滑动
 * @param {number} distance 滑动的距离
 * @param {string} direction 滑动的方向，可以是 'up', 'down', 'left', 'right'
 * @param {number} times 滑动的次数
 * @param {number} [duration=500] 每次滑动的持续时间，单位毫秒
 */
function swipeMultipleTimes(distance, direction, times, duration, margin) {
    if (typeof distance !== 'number' || typeof times !== 'number' || !direction) {
        console.error('Invalid arguments for swipeMultipleTimes');
        return;
    }
    duration = typeof duration !== 'undefined' ? duration : 2000; // ES5 设置默认参数的方法
    let margin = typeof margin !== 'undefined' ? margin : 120
    let startX, startY, endX, endY; // 距离屏幕边缘的最小距离，确保不会太靠近边缘
    for (var i = 0; i < times; i++) {
        switch (direction) {
            case "up":
                startX = endX = device.width / 2;
                startY = device.height - margin;
                endY = Math.max(startY - distance, margin); // 确保终点不低于屏幕顶部边缘
                break;
            case "down":
                startX = endX = device.width / 2;
                startY = margin;
                endY = Math.min(startY + distance, margin); // 确保终点不超过屏幕底部边缘
                break;
            case "left":
                startY = endY = device.height / 2;
                startX = device.width - margin;
                endX = Math.max(startX - distance, margin); // 确保终点不超过屏幕左边缘
                break;
            case "right":
                startY = endY = device.height / 2;
                startX = margin;
                endX = Math.min(startX + distance, screenWidth - margin); // 确保终点不超过屏幕右边缘
                break;
            default:
                console.error("Invalid direction: " + direction);
                return;
        }
        swipe(startX, startY, endX, endY, duration)
        //sml_move(startX, startY, endX, endY, duration); // 使用贝塞尔曲线滑动
    }
}
/**
 * 使用贝塞尔曲线仿真随机带曲线滑动
 * @param {number} qx 起点x坐标
 * @param {number} qy 起点y坐标
 * @param {number} zx 终点x坐标
 * @param {number} zy 终点y坐标
 * @param {number} time 动作耗时（毫秒）
 */
function sml_move(qx, qy, zx, zy, time) {
    let point = [
        { "x": qx, "y": qy },
        { "x": random(qx - 100, qx + 100), "y": random(qy, qy + 50) },
        { "x": random(zx - 100, zx + 100), "y": random(zy, zy + 50) },
        { "x": zx, "y": zy }
    ];

    let xxy = [time];  // Initialize the time array
    for (var i = 0; i <= 1; i += 0.08) {
        let { x, y } = bezier_curves(point, i);
        xxy.push([parseInt(x), parseInt(y)]);
    }

    gesture.apply(null, xxy);  // Execute the swipe gesture
}
/**
 * 计算贝塞尔曲线上某一点的坐标
 * @param {Array} cp 控制点
 * @param {number} t 时间参数（0到1之间）
 * @return {Object} 包含x和y坐标的对象
 */
function bezier_curves(cp, t) {
    let cx = 3.0 * (cp[1].x - cp[0].x);
    let bx = 3.0 * (cp[2].x - cp[1].x) - cx;
    let ax = cp[3].x - cp[0].x - cx - bx;
    let cy = 3.0 * (cp[1].y - cp[0].y);
    let by = 3.0 * (cp[2].y - cp[1].y) - cy;
    let ay = cp[3].y - cp[0].y - cy - by;

    let tSquared = t * t;
    let tCubed = tSquared * t;
    return {
        x: (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x,
        y: (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y
    };
}
/**
 * 递归查找嵌套结构中的满足条件的元素。
 * @param {Element} element        - 当前元素。
 * @param {function} conditionFunc - 动态传入的条件函数，用于判断元素是否符合条件。
 * @param {number} maxDepth        - 最大递归深度。
 * @param {number} currentDepth    - 当前递归深度。
 * @returns {Element|null} 返回找到的符合条件的元素，如果未找到则返回 null。
 */
function findElementRecursively(element, conditionFunc, maxDepth, currentDepth) {
    if (!element || typeof conditionFunc !== 'function') {
        console.error('参数错误', element);
        return null;
    }
    // 设置默认递归深度
    maxDepth = typeof maxDepth !== 'undefined' ? maxDepth : 10;
    currentDepth = typeof currentDepth !== 'undefined' ? currentDepth : 0;

    // 达到最大深度，返回 null
    if (currentDepth >= maxDepth) {
        return null;
    }

    // 判断当前元素是否符合条件
    if (conditionFunc(element)) {
        return element;
    }
    // 使用数组作为栈来模拟递归行为
    var stack = [{ element: element, depth: currentDepth }];

    while (stack.length > 0) {
        var current = stack.pop();
        var currentElement = current.element;
        var depth = current.depth;

        if (conditionFunc(currentElement)) {
            return currentElement;
        }

        // 遍历子元素并入栈
        var children = currentElement.children();
        for (var i = 0; i < children.length; i++) {
            if (depth + 1 < maxDepth) {
                stack.push({ element: children[i], depth: depth + 1 });
            }
        }
    }

    return null; // 如果没有找到符合条件的元素，返回 null
}
/**
 * 递归查找元素的父元素，直到找到满足条件的父元素。
 * @param {Element} element 当前元素。
 * @param {function} conditionFunc 判断父元素是否符合条件的函数。
 * @returns {Element|null} 返回符合条件的父元素，如果未找到则返回 null。
 */
function findParentRecursively(element, conditionFunc) {
    while (element && !conditionFunc(element)) {
        element = element.parent();
    }
    return element || null;
}
/**
 * 更新设备状态。
 * @param {string} deviceId - 设备的唯一标识符。
 * @param {string} status - 新的状态值。
 */
function updateDeviceStatus(deviceId, status) {
    // 构建URL
    let url = '/devices/' + deviceId + '/updateDeviceStatus/' + status;
    // 发送请求并接收响应
    let res = httpRequest(url);
    // 检查响应的状态码
    if (res && res.code === 0) {
        log("----连接服务器成功----");
    } else {
        log("更新失败，状态码：", res ? res.code : '未知错误');
    }

}
/**
 * 更新任务状态。
 * @param {string} taskId - 设备的唯一标识符。
 * @param {string} status - 新的状态值。
 */
function updateTaskStatus(taskId, status) {

    // 构建URL
    let url = '/task/update';
    const json = {
        id: taskId,
        status: status,
        deviceId: getDeviceUniqueId()
    }
    // 发送请求并接收响应
    httpRequest(url, {
        method: 'postJson',
        body: json, notRes: 'yes'
    })
    return true;
}
/**
 * 发送邮件
 * @param {string} message - 邮件内容
 * @param {string} title - 邮件标题
 * @param {boolean} isError - 是否为错误邮件，默认为 false
 */
function sendEmail(message, title, isError) {
    // 默认参数处理
    isError = typeof isError !== 'undefined' ? isError : false;
    title = typeof title !== 'undefined' ? title : "系统消息";
    // 在错误邮件情况下，设置全局标志
    if (isError) {
        SHOULD_STOP = true;
    }
    // 构建邮件内容
    let content = JSON.stringify(message);

    // 构建邮件参数
    let params = {
        deviceId: getDeviceUniqueId(),
        title: title,
        content: content
    };

    // 构建请求选项
    let options = {
        method: 'postJson',
        body: params, notRes: 'yes'
    };
    httpRequest('/system/email', options);


}
/**
 * 获取用户Id
 * @returns {Long} 用户ID
 */
function getUserId() {
    // 从本地存储中获取 user_id
    // let user_id = storage.get("user_id");
    let user_id = null;

    // 如果本地存储中没有 user_id，则通过 HTTP 请求获取
    if (!user_id) {
        const url = '/autoDevice/' + getDeviceUniqueId() + '/user';
        try {
            // 发送 HTTP 请求获取用户信息
            const res = httpRequest(url);

            // 检查请求结果
            if (res.code === 0) {
                user_id = res.data; // 假设 res 已经是对象，不需要再 JSON.parse
                storage.put("user_id", user_id); // 将获取到的 user_id 保存到本地存储中
            } else {
                console.error('Failed to get user ID from server, response code:', res.code);
            }
        } catch (error) {
            console.error('Error fetching user ID:', error);
            sendEmail("获取用户id异常" + error.message, "系统异常！！！", isError);
        }
    }
    // 返回 user_id 或默认值 12345
    return user_id || 12345;
}

/**
 * 获取用户消息
 * @returns {Long} 用户ID
 */
function getUserConfig() {
    // 如果本地存储中没有 user_id，则通过 HTTP 请求获取
    const url = '/autoDevice/' + getDeviceUniqueId() + '/userInfo';
    try {
        // 发送 HTTP 请求获取用户信息
        const res = httpRequest(url);
        // 检查请求结果
        if (res.code === 0) {
            SCREEN_NUM = text(res.data.fans)
            SCREEN_USER_TYPE = text(res.data.type)
            GLOBAL_DELAY = res.data.delay
        }
    } catch (error) {
        console.error('Error fetching user ID:', error);
        sendEmail("获取用户id异常" + error.message, "系统异常！！！", isError);
    }
}
/**
 * 执行任务流程，包括启动应用和执行特定操作。
 * @param {string} taskType - 任务类型，可以是 "TASK_DEFAULT", "TASK_LETTER", "TASK_GATHER", "private_letter"
 * @param {Object} options - 配置和操作参数。
 */
function executeTask(taskType, options) {
    try {

        if (taskType === "TASK_DEFAULT") {
            taskName = "采集"
            toastLog("开始执行采集任务");
        } else if (taskType === "TASK_LETTER") {
            toastLog("开始执行聊天任务");
        }

        // 防止任务冲突
        if (preventTaskConflict()) {
            toastLog("任务冲突");
            return;
        }

        // 启动APP
        if (!SEARCH_BUTTON.exists()) {
            backHome()
        }

        // 根据任务类型执行相应操作
        switch (taskType) {
            case "TASK_DEFAULT":
                collectAndContactUsers(options);
                toastLog("关注任务执行完毕");
                break;
            case "TASK_GATHER":
                options.skipGathering = true;
                collectAndContactUsers(options);
                toastLog("只采集任务执行完毕");
                break;
            case "TASK_LETTER":
                processChatUntilNoMoreMessages(options);
                toastLog("只私信任务执行完毕");
                break;
            default:
                toastLog("未知任务类型: " + taskType);
        }

        IS_RUNNING = false; //停止状态 
        SHOULD_STOP = true; //停止一切运行程序

    } catch (error) {
        console.error("执行任务时发生错误", error);
        IS_RUNNING = false;
        SHOULD_STOP = true;
    }
}

/**
 * 防止任务冲突
 * @returns {boolean} 是否存在任务冲突
 */
function preventTaskConflict() {

    if (IS_RUNNING) {
        sendEmail("任务冲突: " + IS_RUNNING);
        return true;
    }

    TASK_GET_INTERVAL = 0;
    IS_RUNNING = true;
    return false;
}
/**
 * 处理更新任务状态失败的情况，发送错误邮件并重置状态。
 * @param {Number} taskId 任务ID
 */
function handleUpdateTaskStatusError(taskId) {
    sendEmail("关注任务开始执行/获取到任务-更改任务状态出错/任务Id: " + (taskId || 111));
    IS_RUNNING = false;
    SHOULD_STOP = true;
}
var countIndex = 0;
for (let index = 0; index < 35; index++) {

    if (countIndex < 27) {
        countIndex++;
    }

    const NOT_TASK_THRESHOLDS = [3, 9, 27]; // 定义触发任务的阈值

    if (NOT_TASK_THRESHOLDS.includes(countIndex)) {
        log(countIndex)
    }
    log(countIndex)
}



/**
 * 获取新任务，根据任务类型执行相应处理。
 */
function getNewTask() {
    try {
        // 检查是否有任务正在运行，如果有则发送电子邮件并返回
        if (IS_RUNNING) {
            toastLog("任务正在运行");
            return false;
        }

        // 构建请求URL
        const url = '/autoDevice/' + getDeviceUniqueId() + '/newDevice';

        // 发送HTTP请求以获取新任务
        const response = httpRequest(url);
        log("新任务代码", response.data);

        if (response.data && response.data === "DEVICE_NOT_BIND") {
            toastLog("设备未绑定");
            TASK_GET_INTERVAL = 0;
            return false;
        }

        const NOT_TASK_THRESHOLDS = [3, 9, 30]; // 定义触发任务的阈值
        // 处理不同的响应数据
        if (response.data && response.data === "NOT_TASK") {
            toastLog("没有新任务");
            if (NOT_TASK_COUNT < 30) {
                NOT_TASK_COUNT++; //没有任务 加次数
            }

            TASK_GET_INTERVAL = 0;
            longClick(10, 10)

            if (NOT_TASK_THRESHOLDS.includes(NOT_TASK_COUNT)) {
                TASK_QUEUE = 0;
                executeTask("TASK_LETTER", { isUpdate: true });
                if (NOT_TASK_COUNT >= 30) {
                    NOT_TASK_COUNT = 10; // 重置没有任务的计数
                }
            }
            return true;
        }
        if (response && response.code === 0) {
            resJson = JSON.parse(response.data);
            if (resJson.taskSign === "TASK_LETTER") {
                TASK_QUEUE = 0;
            }
            switch (resJson.taskSign) {
                case "TASK_DEFAULT":
                case "TASK_GATHER":
                    executeTask(resJson.taskSign, resJson);
                    TASK_GET_INTERVAL = 23; // 设置获取任务的间隔  
                    NOT_TASK_COUNT = 0; // 重置没有任务的计数  
                    break;
                default:
                    TASK_GET_INTERVAL = 0;
                    toastLog("未知任务: " + resJson.taskSign);
                    break;
            }
            return true;
        } else {
            TASK_GET_INTERVAL = 0;
            return false;
        }
    } catch (e) {
        TASK_GET_INTERVAL = 0;
        console.error('请求新任务时发生错误: ' + e.message);
        return false;
    }
}
/**
 * 检查任务获取间隔并获取新任务
 */
function checkAndFetchNewTask() {
    try {
        toastLog("倒计时" + "" + (TASK_GET_INTERVAL_MAX - TASK_GET_INTERVAL) * 10 + "" + "秒")
        if (TASK_GET_INTERVAL >= TASK_GET_INTERVAL_MAX) {
            sendDeviceStatus()
        }
        // 检查任务获取间隔是否达到 TASK_GET_INTERVAL_MAX 或以上
        if ((TASK_GET_INTERVAL >= TASK_GET_INTERVAL_MAX) && !IS_RUNNING) {
            // 如果没有任务正在运行，尝试获取新任务
            getNewTask();
        } else {
            // 每次执行代码时增加任务获取间隔计数
            TASK_GET_INTERVAL++;
        }

    } catch (error) {
        console.error("checkAndFetchNewTask 错误: " + error);
        sendEmail("checkAndFetchNewTask 错误: " + error.message, "获取新任务异常", true);
    }
}
/**
 * 通用启动应用的函数。
 * @param {string} appName 应用名称。
 * @param {string} appPackage 应用包名。
 * @param {number} [maxRetries=3] 最大重试次数，默认3次。
 * @param {number} [waitTime=10000] 每次重试之间的等待时间，默认10秒。
 * @return {boolean} 如果应用成功启动返回true，否则返回false。
 */
function launchAppWithRetries(appName, appPackage, maxRetries, waitTime) {

    maxRetries = maxRetries || 3;
    waitTime = waitTime || 10000;

    if (currentPackage() === appPackage) {
        return true;
    }

    for (var i = 0; i < maxRetries; i++) {
        if (launchApp(appName)) {
            // 检查应用是否已经启动
            sleep(waitTime);
            if (currentPackage() === appPackage) {
                // toastLog("成功启动 " + appName);
                return true;
            } else {
                console.warn(appName + " 启动后包名不匹配，尝试重启...");
            }
        } else {
            toastLog("启动 " + appName + " 失败，尝试重启...");
        }
        sleep(waitTime);
    }
    toastLog("无法启动 " + appName + "，达到最大重试次数 " + maxRetries);
    return false;
}

/**
 * 获取剪贴板内容的函数，适用于安卓10系统，通过获取焦点来实现。
 * 尝试获取20次，如果未成功则退出。
 * @returns {string} 剪贴板内容或空字符串
 */
function getClips() {
    try {
        // 创建一个不可见的浮动窗口，其中包含一个输入框，用于获取焦点
        let window = floaty.window(
            <frame visibility="invisible">
                <input id="input" />
            </frame>
        );

        // 定义两个变量，用于保存剪贴板内容和最终返回的剪贴板内容
        let getClipX = false;
        let backGetClip = '';

        // 请求焦点，并将焦点设置到输入框
        ui.run(function () {
            window.requestFocus();
            window.input.requestFocus();
        });

        // 定义最大尝试次数
        let maxAttempts = 20;
        let attemptCount = 0;

        // 循环检查剪贴板内容，最多尝试20次
        while (attemptCount < maxAttempts) {
            getClipX = getClip(); // 尝试获取剪贴板内容
            sleep(500); // 等待 500 毫秒

            if (getClipX) { // 如果成功获取到内容
                if (String(getClipX).length > 0) { // 并且内容非空
                    sleep(500); // 再次等待 500 毫秒
                    backGetClip = getClipX; // 保存获取到的剪贴板内容
                    break; // 跳出循环
                } else {
                    log("没有复制成功，再次尝试"); // 记录日志
                }
            } else {
                log("没有复制成功，再次尝试"); // 记录日志
            }

            sleep(200); // 等待 200 毫秒后再次尝试
            attemptCount++; // 增加尝试次数
        }

        // 显示获取到的剪贴板内容或提示未找到内容
        if (backGetClip) {
            // log("已读取粘贴板，内容如下: \n" + backGetClip);
        } else {
            //log("未能成功读取粘贴板内容");
        }

        // 关闭浮动窗口
        ui.run(function () {
            window.close();
        });
        // 返回获取到的剪贴板内容或空字符串
        return backGetClip;
    } catch (error) {
        log(error)
        return null;
    }
}
/**
 * 获取设备的唯一标识符（Android ID）
 * @return {string} 返回设备的唯一标识符，格式为"设备型号_AndroidID"。
 * 如果无法获取有效的Android ID，返回一个默认值或进行错误处理。
 */
function getDeviceUniqueId() {
    // 拼接设备型号和Android ID来形成一个唯一的设备标识符
    let androidId = device.model + "_" + device.getAndroidId();

    // 检查androidId是否为空或未定义，isEmpty为自定义函数，需实现检查逻辑
    if (isEmpty(androidId)) {
        // 如果Android ID为空，可以在这里添加错误处理逻辑，例如抛出错误或返回默认值
        console.error("无法获取Android ID"); // 输出错误信息到控制台
        return "unknown_device"; // 返回一个默认值或进行其他处理
    }

    // 返回构造的设备唯一标识符
    return androidId;
}


/**
 * 尝试关闭弹窗
 * 遍历所有定义的弹窗特征，查找并点击存在的弹窗按钮
 * @returns {boolean} 如果成功关闭了一个弹窗，返回 true，否则返回 false
 */
function closePopup() {
    // let startTime = new Date().getTime(); // 获取当前时间的毫秒数
    toastLog("检查弹窗")
    // 循环遍历 popups 中的所有弹窗特征
    for (var i = 0; i < popups.length; i++) {
        sleep(100)
        let popup = popups[i];
        // 检查是否存在弹窗按钮
        if (popup.query.exists()) {
            // 尝试点击弹窗按钮
            clickElement(popup.selector)
            return true;
        }
    }
    // let endTime = new Date().getTime(); // 获取执行后的当前时间
    // let executionTime = endTime - startTime; // 计算执行时间，单位毫秒
    // console.log("循环遍历 popups", executionTime, "毫秒");
    return false; // 遍历完所有弹窗特征后未能关闭任何弹窗，返回 false
}

/*
==============================================================================================================================================================================================================================================================================
*
* 主函数入口，项目的开始点。
* 
==============================================================================================================================================================================================================================================================================
*/

function main() {
    try {
        init();
        toastLog("初始化成功");
    } catch (error) {
        console.error("项目运行过程中出现错误:", error);
    }
}
/*
==============================================================================================================================================================================================================================================================================
*
* 初始化项目的配置和环境设置。
*
==============================================================================================================================================================================================================================================================================
*/
function init() {
    log("启动时间", new Date().toISOString());
    auto.setWindowFilter(function (window) {
        return true; // 此处可以根据实际情况调整窗口过滤逻辑
    });

}
/** 
 * 返回首页
 */
function backHome() {
    app.startActivity({
        data: "snssdk1128://feed?refer=web&gd_label="
    })
}

/**
 * 强行停止应用 限于安卓
 * @param {*} package  软件包名
 */
function forceStopApp(package) {
    sleep(4000);
    openAppSetting(package);
    sleep(4000);
    let forceStopAppName = textMatches(/(.*强制.*|.*停止.*|.*结束.*)/).findOnce();
    if (forceStopAppName) {
        click(forceStopAppName.bounds().centerX(), forceStopAppName.bounds().centerY());
        sleep(1000)
        if (textContains("强行停止").find().find(boundsInside(0, 950, 1080, 1920))[0] != undefined) {
            //正常情况
            let forceStopApp = textContains("强行停止").find().find(boundsInside(0, 950, 1080, 1920))[0].bounds();
            click(forceStopApp.centerX(), forceStopApp.centerY());
        }
        let confirm = text("确定")
        if (confirm.exists()) {
            clickElement(confirm)
        }
        sleep(1000);
        home()
    } else {
        home()
    }
}
/**
*    搜索栏跳转
* @param {*} str    要跳转的参数 
*/
function sdkSearch(str) {
    app.startActivity({
        action: "android.intent.action.VIEW",
        data: "snssdk1128://search/?keyword=" + str,
        packageName: "com.ss.android.ugc.aweme",
    });
    sleep(random(2000, 8000));
}

/**
*    跳转到用户聊天页
* @param {*} str    要跳转的参数 
*/
function navUserChat(str) {
    app.startActivity({
        action: "android.intent.action.VIEW",
        data: "snssdk1128://chatting/message?uid=" + str,
        packageName: "com.ss.android.ugc.aweme",
    });
    sleep(random(2000, 8000));
}
/**
*    跳转到用户主页
* @param {*} str    要跳转的参数 
*/
function navUserHome(str) {
    app.startActivity({
        action: "android.intent.action.VIEW",
        data: "snssdk1128://user/profile/" + str,
        packageName: "com.ss.android.ugc.aweme",
    });
    sleep(random(2000, 8000));
}
/**
 *   返回首页
*/
function sdkHome() {
    if (!SEARCH_BUTTON.exists() || !HOME_BOTTOM_TEXT.exists()) {
        app.startActivity({
            action: "android.intent.action.MAIN",
            packageName: "com.ss.android.ugc.aweme",
            className: "com.ss.android.ugc.aweme.splash.SplashActivity",
            category: ["android.intent.category.LAUNCHER"],
            flags: ["activity_new_task"]
        });
    }
    sleep(random(2000, 5000));
}
/**
 * 息屏
 */
function breathingPlate() {
    var w = floaty.rawWindow(
        <frame gravity="center" bg="#8A000000" /> // 绿色背景  
    );
    w.setSize(-1, -1); // 设置窗口大小以填满屏幕  
    w.setTouchable(true); // 允许用户交互  
    // 保持脚本运行  
}

/**
 * 获取指定APP版本号 
 * @param {*} package_name 
 * @returns  number
 */
function getVersion(package_name) {
    let pkgs = context.getPackageManager().getInstalledPackages(0).toArray();
    for (let i in pkgs) {
        if (pkgs[i].packageName.toString() === package_name) {
            return pkgs[i].versionName;
        }
    }
}
// 写入数据到文件，一行一行地存
function writeLineToFile(line) {
    if (!line || line === undefined || line === 'undefined' || line.includes("/")) {
        console.error("无效数据line: ", line);
        return;
    }

    ensureFileExists(notChatPath); // 确保文件存在
    let lines = readFileContent().split("$").filter(line => line.trim() !== ""); // 读取文件内容并转换为数组
    if (lines.includes(line)) {
        console.error("数据已存在line: " + line);
        return;
    }
    let file = open(notChatPath, "a"); // 以追加模式打开文件
    file.write(line + "$"); // 写入数据
    file.close(); // 关闭文件
    log("数据已插入: " + line);
}
// 读取文件内容
function readFileContent() {
    let file = open(notChatPath, "r"); // 以读取模式打开文件
    let content = file.read(); // 读取文件内容
    file.close(); // 关闭文件
    return content;
}
// 删除指定行
function deleteLine(lineNumber) {
    try {
        let lines = readFileContent().split("$").filter(line => line.trim() !== ""); // 读取文件内容并转换为数组
        if (lineNumber < 1 || lineNumber > lines.length) {
            log("行号超出范围", lineNumber);
            return;
        }
        lines.splice(lineNumber - 1, 1); // 删除指定行
        let file = open(notChatPath, "w"); // 以写入模式打开文件，清空文件内容
        file.write(lines.join("$") + "$");
        file.close();
        return true;
    } catch (error) {
        console.error("删除聊天用户行失败", error);
        return false;
    }

}
// 确保文件存在，如果不存在则创建
function ensureFileExists(filePath) {
    let file = open(filePath, "a"); // 以追加模式打开文件，如果不存在则创建
    file.close(); // 关闭文件
}
/**
 * 往服务器发送  设备状态
 */
function sendDeviceStatus() {
    httpRequest('/devices/getDeviceStatus/' + getDeviceUniqueId(), { notRes: 'yes' })
}
/*
==============================================================================================================================================================================================================================================================================
*
* 设置全局的事件监听器，如界面变化、网络状态变化等。
*
==============================================================================================================================================================================================================================================================================
*/
function setupListeners() {
    let versionNum = getVersion(appPackage)
    if (versionNum !== '29.7.0') {
        toastLog("抖音版本号不对 /不予以启动" + "" + versionNum)
        return;
    }
    checkAndFetchNewTask()
}
// 示例用法
// files.remove(notChatPath);
// mainSwitch = true; // 全局开关，用于控制是否启动脚本
if (!mainSwitch) {
    let START = setInterval(() => { setupListeners() }, 10 * 1000)
    main()
}



